home *** CD-ROM | disk | FTP | other *** search
/ MacWorld 2003 August / MW 8 2003 CD1.iso / Inside Macworld / Product News / gimp-1.2.4.sit / gimp-1.2.4 / app / edit_selection.c < prev    next >
Encoding:
C/C++ Source or Header  |  2003-05-08  |  23.1 KB  |  858 lines

  1. /* The GIMP -- an image manipulation program
  2.  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
  3.  *
  4.  * This program is free software; you can redistribute it and/or modify
  5.  * it under the terms of the GNU General Public License as published by
  6.  * the Free Software Foundation; either version 2 of the License, or
  7.  * (at your option) any later version.
  8.  *
  9.  * This program is distributed in the hope that it will be useful,
  10.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.  * GNU General Public License for more details.
  13.  *
  14.  * You should have received a copy of the GNU General Public License
  15.  * along with this program; if not, write to the Free Software
  16.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  17.  */
  18.  
  19. #include "config.h"
  20.  
  21. #include <stdlib.h>
  22. #include <stdarg.h>
  23.  
  24. #include <gtk/gtk.h>
  25. #include <gdk/gdkkeysyms.h>
  26.  
  27. #include "apptypes.h"
  28.  
  29. #include "appenv.h"
  30. #include "cursorutil.h"
  31. #include "draw_core.h"
  32. #include "drawable.h"
  33. #include "tools.h"
  34. #include "edit_selection.h"
  35. #include "floating_sel.h"
  36. #include "gimage_mask.h"
  37. #include "gdisplay.h"
  38. #include "undo.h"
  39. #include "gimprc.h"
  40. #include "path_transform.h"
  41.  
  42. #include "libgimp/gimpintl.h"
  43. #include "libgimp/gimpmath.h"
  44.  
  45.  
  46. #define EDIT_SELECT_SCROLL_LOCK FALSE
  47. #define ARROW_VELOCITY          25
  48. #define STATUSBAR_SIZE          128
  49.  
  50.  
  51. typedef struct _EditSelection EditSelection;
  52. struct _EditSelection
  53. {
  54.   gint                origx, origy;      /*  last x and y coords             */
  55.   gint                cumlx, cumly;      /*  cumulative changes to x and yed */
  56.   gint                x, y;              /*  current x and y coords          */
  57.   gint                num_segs_in;       /* Num seg in selection boundary    */
  58.   gint                num_segs_out;      /* Num seg in selection boundary    */
  59.   BoundSeg           *segs_in;           /* Pointer to the channel sel. segs */
  60.   BoundSeg           *segs_out;          /* Pointer to the channel sel. segs */
  61.  
  62.   gint                x1, y1;            /*  bounding box of selection mask  */
  63.   gint                x2, y2;
  64.  
  65.   EditType            edit_type;         /*  translate the mask or layer?    */
  66.  
  67.   DrawCore           *core;              /* selection core for drawing bounds*/
  68.  
  69.   ButtonReleaseFunc   old_button_release;/*  old button press member func    */
  70.   MotionFunc          old_motion;        /*  old motion member function      */
  71.   ToolCtlFunc         old_control;       /*  old control member function     */
  72.   CursorUpdateFunc    old_cursor_update; /*  old cursor update function      */
  73.   gboolean            old_scroll_lock;   /*  old value of scroll lock        */
  74.   gboolean            old_auto_snap_to;  /*  old value of auto snap to       */
  75.  
  76.   gboolean            first_move;        /*  we undo_freeze after the first  */
  77.  
  78.   guint               context_id;        /*  for the statusbar               */
  79. };
  80.  
  81.  
  82. /*  static EditSelection structure -- there is ever only one present  */
  83. static EditSelection edit_select;
  84.  
  85.  
  86. static void
  87. edit_selection_snap (GDisplay *gdisp,
  88.              gdouble   x,
  89.              gdouble   y)
  90. {
  91.   gdouble x1, y1;
  92.   gdouble x2, y2;
  93.   gdouble dx, dy;
  94.  
  95.   gdisplay_untransform_coords_f (gdisp, x, y, &x, &y, TRUE);
  96.  
  97.   dx = x - edit_select.origx;
  98.   dy = y - edit_select.origy;
  99.  
  100.   x1 = edit_select.x1 + dx;
  101.   y1 = edit_select.y1 + dy;
  102.  
  103.   if (gdisp->draw_guides &&
  104.       gdisp->snap_to_guides &&
  105.       gdisp->gimage->guides)
  106.     {
  107.       x2 = edit_select.x2 + dx;
  108.       y2 = edit_select.y2 + dy;
  109.   
  110.       gdisplay_transform_coords_f (gdisp, x1, y1, &x1, &y1, TRUE);
  111.       gdisplay_transform_coords_f (gdisp, x2, y2, &x2, &y2, TRUE);
  112.       
  113.       gdisplay_snap_rectangle (gdisp, x1, y1, x2, y2, &x1, &y1);
  114.       
  115.       gdisplay_untransform_coords_f (gdisp, x1, y1, &x1, &y1, TRUE);
  116.     }
  117.  
  118.   edit_select.x = (gint) floor (x1) - (edit_select.x1 - edit_select.origx);
  119.   edit_select.y = (gint) floor (y1) - (edit_select.y1 - edit_select.origy);
  120. }
  121.  
  122. void
  123. init_edit_selection (Tool           *tool,
  124.              gpointer        gdisp_ptr,
  125.              GdkEventButton *bevent,
  126.              EditType        edit_type)
  127. {
  128.   GDisplay *gdisp;
  129.   Layer *layer;
  130.   gint x, y;
  131.  
  132.   gdisp = (GDisplay *) gdisp_ptr;
  133.  
  134.   undo_push_group_start (gdisp->gimage, LAYER_DISPLACE_UNDO);
  135.  
  136.   /*  Move the (x, y) point from screen to image space  */
  137.   gdisplay_untransform_coords (gdisp, 
  138.                    bevent->x, bevent->y, &x, &y, FALSE, TRUE);
  139.  
  140.   edit_select.x = edit_select.origx = x;
  141.   edit_select.y = edit_select.origy = y;
  142.  
  143.   edit_select.cumlx = 0;
  144.   edit_select.cumly = 0;
  145.  
  146.   gimage_mask_boundary (gdisp->gimage, &edit_select.segs_in, 
  147.             &edit_select.segs_out,
  148.             &edit_select.num_segs_in, 
  149.             &edit_select.num_segs_out);
  150.  
  151.   /*  Make a check to see if it should be a floating selection translation  */
  152.   if (edit_type == EDIT_MASK_TO_LAYER_TRANSLATE && gimage_floating_sel (gdisp->gimage))
  153.     edit_type = EDIT_FLOATING_SEL_TRANSLATE;
  154.  
  155.   if (edit_type == EDIT_LAYER_TRANSLATE)
  156.     {
  157.       layer = gimage_get_active_layer (gdisp->gimage);
  158.       if (layer_is_floating_sel (layer))
  159.     edit_type = EDIT_FLOATING_SEL_TRANSLATE;
  160.     }
  161.  
  162.   edit_select.edit_type = edit_type;
  163.  
  164.   edit_select.old_button_release = tool->button_release_func;
  165.   edit_select.old_motion         = tool->motion_func;
  166.   edit_select.old_control        = tool->control_func;
  167.   edit_select.old_cursor_update  = tool->cursor_update_func;
  168.   edit_select.old_scroll_lock    = tool->scroll_lock;
  169.   edit_select.old_auto_snap_to   = tool->auto_snap_to;
  170.  
  171.   edit_select.first_move         = TRUE;
  172.  
  173.   /*  find the bounding box of the selection mask -
  174.    *  this is used for the case of a EDIT_MASK_TO_LAYER_TRANSLATE,
  175.    *  where the translation will result in floating the selection
  176.    *  mask and translating the resulting layer
  177.    */
  178.   drawable_mask_bounds (gimage_active_drawable (gdisp->gimage),
  179.             &edit_select.x1, &edit_select.y1,
  180.             &edit_select.x2, &edit_select.y2);
  181.  
  182.   edit_selection_snap (gdisp, bevent->x, bevent->y);
  183.  
  184.   /*  reset the function pointers on the selection tool  */
  185.   tool->button_release_func = edit_selection_button_release;
  186.   tool->motion_func         = edit_selection_motion;
  187.   tool->control_func        = edit_selection_control;
  188.   tool->cursor_update_func  = edit_selection_cursor_update;
  189.   tool->scroll_lock         = EDIT_SELECT_SCROLL_LOCK;
  190.   tool->auto_snap_to        = FALSE;
  191.  
  192.   /*  pause the current selection  */
  193.   selection_pause (gdisp->select);
  194.  
  195.   /* initialize the statusbar display */
  196.   edit_select.context_id 
  197.     = gtk_statusbar_get_context_id (GTK_STATUSBAR (gdisp->statusbar), 
  198.                     "edit_select");
  199.   gtk_statusbar_push (GTK_STATUSBAR (gdisp->statusbar), 
  200.               edit_select.context_id, 
  201.               _("Move: 0, 0"));
  202.  
  203.   /*  Create and start the selection core  */
  204.   edit_select.core = draw_core_new (edit_selection_draw);
  205.   draw_core_start (edit_select.core,
  206.            gdisp->canvas->window,
  207.            tool);
  208. }
  209.  
  210.  
  211. void
  212. edit_selection_button_release (Tool           *tool,
  213.                    GdkEventButton *bevent,
  214.                    gpointer        gdisp_ptr)
  215. {
  216.   gint      x;
  217.   gint      y;
  218.   GDisplay *gdisp;
  219.   Layer    *layer;
  220.  
  221.   gdisp = (GDisplay *) gdisp_ptr;
  222.  
  223.   /*  resume the current selection and ungrab the pointer  */
  224.   selection_resume (gdisp->select);
  225.  
  226.   gdk_pointer_ungrab (bevent->time);
  227.   gdk_flush ();
  228.  
  229.   gtk_statusbar_pop (GTK_STATUSBAR (gdisp->statusbar), edit_select.context_id);
  230.  
  231.   /*  Stop and free the selection core  */
  232.   draw_core_stop (edit_select.core, tool);
  233.   draw_core_free (edit_select.core);
  234.   edit_select.core = NULL;
  235.   tool->state      = INACTIVE;
  236.  
  237.   tool->button_release_func = edit_select.old_button_release;
  238.   tool->motion_func         = edit_select.old_motion;
  239.   tool->control_func        = edit_select.old_control;
  240.   tool->cursor_update_func  = edit_select.old_cursor_update;
  241.   tool->scroll_lock         = edit_select.old_scroll_lock;
  242.   tool->auto_snap_to        = edit_select.old_auto_snap_to;
  243.  
  244.   /* EDIT_MASK_TRANSLATE is performed here at movement end, not 'live' like
  245.    *  the other translation types.
  246.    */
  247.   if (edit_select.edit_type == EDIT_MASK_TRANSLATE)
  248.     {
  249.       edit_selection_snap (gdisp, bevent->x, bevent->y);
  250.       x = edit_select.x;
  251.       y = edit_select.y;
  252.       
  253.       /* move the selection -- whether there has been net movement or not!
  254.        * (to ensure that there's something on the undo stack)
  255.        */
  256.       gimage_mask_translate (gdisp->gimage, 
  257.                  edit_select.cumlx,
  258.                  edit_select.cumly);
  259.       
  260.       if (edit_select.first_move)
  261.     {
  262.       gimp_image_undo_freeze (gdisp->gimage);
  263.       edit_select.first_move = FALSE;
  264.     }
  265.     }
  266.   
  267.   /* thaw the undo again */
  268.   gimp_image_undo_thaw (gdisp->gimage);
  269.  
  270.   if (edit_select.cumlx != 0 || edit_select.cumly != 0)
  271.     {
  272.       path_transform_xy (gdisp->gimage, edit_select.cumlx, edit_select.cumly);
  273.  
  274.       layer = gimage_get_active_layer (gdisp->gimage);
  275.       gimp_drawable_invalidate_preview (GIMP_DRAWABLE (layer), TRUE);
  276.     }
  277.     
  278.   undo_push_group_end (gdisp->gimage);
  279.  
  280.   if (bevent->state & GDK_BUTTON3_MASK) /* OPERATION CANCELLED */
  281.     {
  282.       /* Operation cancelled - undo the undo-group! */
  283.       undo_pop (gdisp->gimage);
  284.     }
  285.  
  286.   gdisplays_flush ();
  287. }
  288.  
  289.  
  290. void
  291. edit_selection_motion (Tool           *tool,
  292.                GdkEventMotion *mevent,
  293.                gpointer        gdisp_ptr)
  294. {
  295.   GDisplay * gdisp;
  296.   gchar offset[STATUSBAR_SIZE];
  297.   gdouble lastmotion_x, lastmotion_y;
  298.  
  299.   if (tool->state != ACTIVE)
  300.     {
  301.       g_warning ("BUG: Tracking motion while !ACTIVE");
  302.       return;
  303.     }
  304.  
  305.   gdisp = (GDisplay *) gdisp_ptr;
  306.  
  307.   gdk_flush ();
  308.  
  309.   draw_core_pause (edit_select.core, tool);
  310.  
  311.  
  312.   /* Perform motion compression so that we don't lag and/or waste time. */
  313.  
  314.   if (!gtkutil_compress_motion (gtk_get_event_widget ((GdkEvent*) mevent),
  315.                 &lastmotion_x, &lastmotion_y))
  316.     {
  317.       lastmotion_x = mevent->x;
  318.       lastmotion_y = mevent->y;
  319.     }
  320.  
  321.   /* now do the actual move. */
  322.  
  323.   edit_selection_snap (gdisp, lastmotion_x, lastmotion_y);
  324.  
  325.   /******************************************* adam's live move *******/
  326.   /********************************************************************/
  327.   {
  328.     gint    x, y;
  329.     Layer  *layer;
  330.     Layer  *floating_layer;
  331.     GSList *layer_list;
  332.  
  333.     x = edit_select.x;
  334.     y = edit_select.y;
  335.  
  336.     /* if there has been movement, move the selection  */
  337.     if (edit_select.origx != x || edit_select.origy != y)
  338.       {
  339.     gint xoffset, yoffset;
  340.     
  341.     xoffset = x - edit_select.origx;
  342.     yoffset = y - edit_select.origy;
  343.  
  344.     edit_select.cumlx += xoffset;
  345.     edit_select.cumly += yoffset;
  346.  
  347.     switch (edit_select.edit_type)
  348.       {
  349.       case EDIT_MASK_TRANSLATE:
  350.         /*  we don't do the actual edit selection move here.  */
  351.         edit_select.origx = x;
  352.         edit_select.origy = y;
  353.         break;
  354.     
  355.       case EDIT_LAYER_TRANSLATE:
  356.         if ((floating_layer = gimage_floating_sel (gdisp->gimage)))
  357.           floating_sel_relax (floating_layer, TRUE);
  358.       
  359.         /*  translate the layer--and any "linked" layers as well  */
  360.         for (layer_list = gdisp->gimage->layers;
  361.          layer_list;
  362.          layer_list = g_slist_next (layer_list))
  363.           {
  364.         layer = (Layer *) layer_list->data;
  365.         if (layer == gdisp->gimage->active_layer || 
  366.             layer_linked (layer))
  367.           {
  368.             layer_translate (layer, xoffset, yoffset);
  369.           }
  370.           }
  371.       
  372.         if (floating_layer)
  373.           floating_sel_rigor (floating_layer, TRUE);
  374.  
  375.         if (edit_select.first_move)
  376.           {
  377.         gimp_image_undo_freeze (gdisp->gimage);
  378.         edit_select.first_move = FALSE;
  379.           }
  380.         break;
  381.     
  382.       case EDIT_MASK_TO_LAYER_TRANSLATE:
  383.         if (!gimage_mask_float (gdisp->gimage, 
  384.                     gimage_active_drawable (gdisp->gimage),
  385.                     0, 0))
  386.           {
  387.         /* no region to float, abort safely */
  388.          draw_core_resume (edit_select.core, tool);
  389.          return;
  390.           }
  391.  
  392.         /* this is always the first move, since we switch to 
  393.            EDIT_FLOATING_SEL_TRANSLATE when finished here */
  394.         gimp_image_undo_freeze (gdisp->gimage);
  395.         edit_select.first_move = FALSE; 
  396.  
  397.         edit_select.origx -= edit_select.x1;
  398.         edit_select.origy -= edit_select.y1;
  399.         edit_select.x2 -= edit_select.x1;
  400.         edit_select.y2 -= edit_select.y1;
  401.         edit_select.x1 = 0;
  402.         edit_select.y1 = 0;
  403.  
  404.         edit_select.edit_type = EDIT_FLOATING_SEL_TRANSLATE;
  405.             /*  Don't break, fall through.  */
  406.  
  407.       case EDIT_FLOATING_SEL_TRANSLATE:
  408.         layer = gimage_get_active_layer (gdisp->gimage);
  409.       
  410.         floating_sel_relax (layer, TRUE);
  411.         layer_translate (layer, xoffset, yoffset);
  412.         floating_sel_rigor (layer, TRUE);
  413.  
  414.         if (edit_select.first_move)
  415.           {
  416.         gimp_image_undo_freeze (gdisp->gimage);
  417.         edit_select.first_move = FALSE;
  418.           }
  419.         break;
  420.  
  421.       default:
  422.         g_warning ("esm / BAD FALLTHROUGH");
  423.       }
  424.       }
  425.  
  426.     gdisplay_flush (gdisp);
  427.   }
  428.   /********************************************************************/
  429.   /********************************************************************/
  430.   
  431.  
  432.   gtk_statusbar_pop (GTK_STATUSBAR (gdisp->statusbar), edit_select.context_id);
  433.   if (gdisp->dot_for_dot)
  434.     {
  435.       g_snprintf (offset, STATUSBAR_SIZE, gdisp->cursor_format_str,
  436.           _("Move: "),
  437.           edit_select.cumlx,
  438.           ", ",
  439.           edit_select.cumly);
  440.     }
  441.   else /* show real world units */
  442.     {
  443.       gdouble unit_factor = gimp_unit_get_factor (gdisp->gimage->unit);
  444.  
  445.       g_snprintf (offset, STATUSBAR_SIZE, gdisp->cursor_format_str,
  446.           _("Move: "), 
  447.           (edit_select.cumlx) * unit_factor / 
  448.           gdisp->gimage->xresolution,
  449.           ", ",
  450.           (edit_select.cumly) * unit_factor /
  451.           gdisp->gimage->yresolution);
  452.     }
  453.   gtk_statusbar_push (GTK_STATUSBAR (gdisp->statusbar), edit_select.context_id,
  454.               offset);
  455.  
  456.   draw_core_resume (edit_select.core, tool);
  457. }
  458.  
  459. static void
  460. selection_transform_segs (GDisplay   *gdisp,
  461.               BoundSeg   *src_segs,
  462.               GdkSegment *dest_segs,
  463.               gint        num_segs)
  464. {
  465.   gint x, y;
  466.   gint i;
  467.  
  468.   for (i = 0; i < num_segs; i++)
  469.     {
  470.       gdisplay_transform_coords (gdisp, 
  471.                  src_segs[i].x1 + edit_select.cumlx, 
  472.                  src_segs[i].y1 + edit_select.cumly,
  473.                  &x, &y, FALSE);
  474.  
  475.       dest_segs[i].x1 = x;
  476.       dest_segs[i].y1 = y;
  477.  
  478.       gdisplay_transform_coords (gdisp, 
  479.                  src_segs[i].x2 + edit_select.cumlx, 
  480.                  src_segs[i].y2 + edit_select.cumly,
  481.                  &x, &y, FALSE);
  482.  
  483.       dest_segs[i].x2 = x;
  484.       dest_segs[i].y2 = y;
  485.  
  486.     }
  487. }
  488.  
  489. void
  490. edit_selection_draw (Tool *tool)
  491. {
  492.   GDisplay * gdisp;
  493.   Selection * select;
  494.   Layer *layer;
  495.   GSList *layer_list;
  496.   gint floating_sel;
  497.   gint x1, y1, x2, y2;
  498.   gint x3, y3, x4, y4;
  499.   gint off_x, off_y;
  500.   GdkSegment *segs_copy;
  501.  
  502.   gdisp = (GDisplay *) tool->gdisp_ptr;
  503.   select = gdisp->select;
  504.  
  505.   switch (edit_select.edit_type)
  506.     {
  507.     case EDIT_MASK_TRANSLATE:
  508.       layer = gimage_get_active_layer (gdisp->gimage);
  509.       floating_sel = layer_is_floating_sel (layer);
  510.  
  511.       if (!floating_sel)
  512.     {
  513.        segs_copy = g_new (GdkSegment, edit_select.num_segs_in);
  514.  
  515.        selection_transform_segs (gdisp,
  516.                      edit_select.segs_in,
  517.                      segs_copy,
  518.                      edit_select.num_segs_in);
  519.       
  520.        /*  Draw the items  */
  521.        gdk_draw_segments (edit_select.core->win, edit_select.core->gc,
  522.                   segs_copy, select->num_segs_in);
  523.        
  524.        g_free (segs_copy);
  525.     }
  526.  
  527.       segs_copy = g_new (GdkSegment, edit_select.num_segs_out);
  528.       
  529.       selection_transform_segs (gdisp,
  530.                 edit_select.segs_out,
  531.                 segs_copy,
  532.                 edit_select.num_segs_out);
  533.       
  534.       /*  Draw the items  */
  535.       gdk_draw_segments (edit_select.core->win, edit_select.core->gc,
  536.              segs_copy, select->num_segs_out);
  537.  
  538.       g_free (segs_copy);
  539.       break;
  540.  
  541.     case EDIT_MASK_TO_LAYER_TRANSLATE:
  542.       gdisplay_transform_coords (gdisp, 
  543.                  edit_select.x1, edit_select.y1, 
  544.                  &x1, &y1, TRUE);
  545.       gdisplay_transform_coords (gdisp, 
  546.                  edit_select.x2, edit_select.y2, 
  547.                  &x2, &y2, TRUE);
  548.       if (x2 > x1 && y2 > y1)
  549.         gdk_draw_rectangle (edit_select.core->win,
  550.                             edit_select.core->gc, FALSE,
  551.                             x1, y1,
  552.                             x2 - x1 - 1, y2 - y1 - 1);
  553.       break;
  554.  
  555.     case EDIT_LAYER_TRANSLATE:
  556.       gdisplay_transform_coords (gdisp, 0, 0, &x1, &y1, TRUE);
  557.       gdisplay_transform_coords (gdisp,
  558.                  drawable_width (GIMP_DRAWABLE (gdisp->gimage->active_layer)),
  559.                  drawable_height (GIMP_DRAWABLE (gdisp->gimage->active_layer)),
  560.                  &x2, &y2, TRUE);
  561.  
  562.       /*  Now, expand the rectangle to include all linked layers as well  */
  563.       for (layer_list= gdisp->gimage->layers;
  564.        layer_list;
  565.        layer_list = g_slist_next (layer_list))
  566.     {
  567.       layer = (Layer *) layer_list->data;
  568.       if (((layer) != gdisp->gimage->active_layer) && layer_linked (layer))
  569.         {
  570.           drawable_offsets (GIMP_DRAWABLE (layer), &off_x, &off_y);
  571.           gdisplay_transform_coords (gdisp, off_x, off_y, &x3, &y3, FALSE);
  572.           gdisplay_transform_coords (gdisp,
  573.                      off_x + drawable_width (GIMP_DRAWABLE (layer)),
  574.                      off_y + drawable_height (GIMP_DRAWABLE (layer)),
  575.                      &x4, &y4, FALSE);
  576.           if (x3 < x1)
  577.         x1 = x3;
  578.           if (y3 < y1)
  579.         y1 = y3;
  580.           if (x4 > x2)
  581.         x2 = x4;
  582.           if (y4 > y2)
  583.         y2 = y4;
  584.         }
  585.     }
  586.  
  587.       if (x2 > x1 && y2 > y1)
  588.         gdk_draw_rectangle (edit_select.core->win,
  589.                             edit_select.core->gc, FALSE,
  590.                             x1, y1,
  591.                             x2 - x1 - 1, y2 - y1 - 1);
  592.       break;
  593.  
  594.     case EDIT_FLOATING_SEL_TRANSLATE:
  595.       segs_copy = g_new (GdkSegment, edit_select.num_segs_in);
  596.  
  597.       /* The selection segs are in image space convert these 
  598.        * to display space.
  599.        * Takes care of offset/zoom etc etc.
  600.        */
  601.  
  602.       selection_transform_segs (gdisp,
  603.                 edit_select.segs_in,
  604.                 segs_copy,
  605.                 edit_select.num_segs_in);
  606.       
  607.       /*  Draw the items  */
  608.       gdk_draw_segments (edit_select.core->win, edit_select.core->gc,
  609.              segs_copy, select->num_segs_in);
  610.  
  611.       g_free (segs_copy);
  612.       break;
  613.     }
  614. }
  615.  
  616.  
  617. void
  618. edit_selection_control (Tool       *tool,
  619.             ToolAction  action,
  620.             gpointer    gdisp_ptr)
  621. {
  622.   switch (action)
  623.     {
  624.     case PAUSE:
  625.       draw_core_pause (edit_select.core, tool);
  626.       break;
  627.  
  628.     case RESUME:
  629.       draw_core_resume (edit_select.core, tool);
  630.       break;
  631.  
  632.     case HALT:
  633.       draw_core_stop (edit_select.core, tool);
  634.       draw_core_free (edit_select.core);
  635.       break;
  636.  
  637.     default:
  638.       break;
  639.     }
  640. }
  641.  
  642.  
  643. void
  644. edit_selection_cursor_update (Tool           *tool,
  645.                   GdkEventMotion *mevent,
  646.                   gpointer        gdisp_ptr)
  647. {
  648.   GDisplay *gdisp;
  649.  
  650.   gdisp = (GDisplay *) gdisp_ptr;
  651.   gdisplay_install_tool_cursor (gdisp, GIMP_MOUSE_CURSOR,
  652.                 TOOL_TYPE_NONE,
  653.                 CURSOR_MODIFIER_MOVE,
  654.                 FALSE);
  655. }
  656.  
  657. static gint
  658. process_event_queue_keys (GdkEventKey *kevent, 
  659.               ...)
  660. /* GdkKeyType, GdkModifierType, value ... 0 
  661.  * could move this function to a more central location so it can be used
  662.  * by other tools? */
  663. {
  664. #define FILTER_MAX_KEYS 50
  665.   va_list argp;
  666.   GdkEvent *event;
  667.   GList *event_list = NULL;
  668.   GList *list;
  669.   guint keys[FILTER_MAX_KEYS];
  670.   GdkModifierType modifiers[FILTER_MAX_KEYS];
  671.   gint values[FILTER_MAX_KEYS];
  672.   gint i = 0, nkeys = 0, value = 0;
  673.   gboolean done = FALSE;
  674.   gboolean discard_event;
  675.   GtkWidget *orig_widget;
  676.  
  677.   va_start (argp, kevent);
  678.   while (nkeys <FILTER_MAX_KEYS && (keys[nkeys] = va_arg (argp, guint)) != 0)
  679.     {
  680.       modifiers[nkeys] = va_arg (argp, GdkModifierType);
  681.       values[nkeys]    = va_arg (argp, gint);
  682.       nkeys++;
  683.     }
  684.   va_end(argp);
  685.  
  686.   for (i = 0; i < nkeys; i++)
  687.     {
  688.       if (kevent->keyval == keys[i] && kevent->state == modifiers[i])
  689.     value += values[i];
  690.     }
  691.  
  692.   orig_widget = gtk_get_event_widget ((GdkEvent*) kevent);
  693.  
  694.   while (gdk_events_pending () > 0 && !done)
  695.   {
  696.     discard_event = FALSE;
  697.     event = gdk_event_get ();
  698.  
  699.     if (!event || orig_widget != gtk_get_event_widget (event))
  700.       {
  701.     done = TRUE;
  702.       }
  703.     else
  704.       {
  705.     if (event->any.type == GDK_KEY_PRESS)
  706.       {
  707.         for (i = 0; i < nkeys; i++)
  708.           if (event->key.keyval == keys[i] &&
  709.           event->key.state  == modifiers[i])
  710.         {
  711.           discard_event = TRUE;
  712.           value += values[i];
  713.         }
  714.  
  715.         if (!discard_event)
  716.           done = TRUE;
  717.       }
  718.          /* should there be more types here? */
  719.     else if (event->any.type != GDK_KEY_RELEASE &&
  720.          event->any.type != GDK_MOTION_NOTIFY &&
  721.          event->any.type != GDK_EXPOSE)
  722.       done = FALSE;
  723.       }
  724.  
  725.     if (!event)
  726.       ; /* Do nothing */
  727.     else if (!discard_event)
  728.       event_list = g_list_prepend (event_list, event);
  729.     else
  730.       gdk_event_free (event);
  731.   }
  732.  
  733.   event_list = g_list_reverse (event_list);
  734.  
  735.   /* unget the unused events and free the list */
  736.   for (list = event_list;
  737.        list;
  738.        list = g_list_next (list))
  739.     {
  740.       gdk_event_put ((GdkEvent*)list->data);
  741.       gdk_event_free ((GdkEvent*)list->data);
  742.     }
  743.  
  744.   g_list_free (event_list);
  745.  
  746.   return value;
  747. #undef FILTER_MAX_KEYS
  748. }
  749.  
  750. void
  751. edit_sel_arrow_keys_func (Tool        *tool,
  752.               GdkEventKey *kevent,
  753.               gpointer     gdisp_ptr)
  754. {
  755.   gint inc_x, inc_y, mask_inc_x, mask_inc_y;
  756.   GDisplay *gdisp;
  757.   Layer *layer;
  758.   Layer *floating_layer;
  759.   GSList *layer_list;
  760.   EditType edit_type;
  761.  
  762.   layer = NULL;
  763.  
  764.   gdisp = (GDisplay *) gdisp_ptr;
  765.  
  766.   inc_x = 
  767.     process_event_queue_keys (kevent,
  768.                   GDK_Left,  0,              -1, 
  769.                   GDK_Left,  GDK_SHIFT_MASK, -1 * ARROW_VELOCITY, 
  770.                   GDK_Right, 0,               1, 
  771.                   GDK_Right, GDK_SHIFT_MASK,  1 * ARROW_VELOCITY, 
  772.                   0);
  773.   inc_y = 
  774.     process_event_queue_keys (kevent,
  775.                   GDK_Up,   0,              -1, 
  776.                   GDK_Up,   GDK_SHIFT_MASK, -1 * ARROW_VELOCITY, 
  777.                   GDK_Down, 0,               1, 
  778.                   GDK_Down, GDK_SHIFT_MASK,  1 * ARROW_VELOCITY, 
  779.                   0);
  780.   
  781.   mask_inc_x = 
  782.     process_event_queue_keys (kevent,
  783.                   GDK_Left,  GDK_MOD1_MASK,                    -1, 
  784.                   GDK_Left,  (GDK_MOD1_MASK | GDK_SHIFT_MASK), -1 * ARROW_VELOCITY, 
  785.                   GDK_Right, GDK_MOD1_MASK,                     1, 
  786.                   GDK_Right, (GDK_MOD1_MASK | GDK_SHIFT_MASK),  1 * ARROW_VELOCITY, 
  787.                   0);
  788.   mask_inc_y = 
  789.     process_event_queue_keys (kevent,
  790.                   GDK_Up,   GDK_MOD1_MASK,                    -1, 
  791.                   GDK_Up,   (GDK_MOD1_MASK | GDK_SHIFT_MASK), -1 * ARROW_VELOCITY, 
  792.                   GDK_Down, GDK_MOD1_MASK,                     1, 
  793.                   GDK_Down, (GDK_MOD1_MASK | GDK_SHIFT_MASK),  1 * ARROW_VELOCITY, 
  794.                   0);
  795.  
  796.   if (inc_x == 0 && inc_y == 0  &&  mask_inc_x == 0 && mask_inc_y == 0)
  797.     return;
  798.  
  799.   undo_push_group_start (gdisp->gimage, LAYER_DISPLACE_UNDO);
  800.  
  801.   if (mask_inc_x != 0 || mask_inc_y != 0)
  802.     gimage_mask_translate (gdisp->gimage, mask_inc_x, mask_inc_y);
  803.  
  804.   if (inc_x != 0 || inc_y != 0)
  805.     {
  806.       layer = gimage_get_active_layer (gdisp->gimage);
  807.  
  808.       if (layer_is_floating_sel (layer))
  809.     edit_type = EDIT_FLOATING_SEL_TRANSLATE;
  810.       else
  811.     edit_type = EDIT_LAYER_TRANSLATE;
  812.       
  813.       switch (edit_type)
  814.     {
  815.     case EDIT_MASK_TRANSLATE:
  816.     case EDIT_MASK_TO_LAYER_TRANSLATE:
  817.       /*  this won't happen  */
  818.       break;
  819.  
  820.     case EDIT_LAYER_TRANSLATE:
  821.       
  822.       if ((floating_layer = gimage_floating_sel (gdisp->gimage)))
  823.         floating_sel_relax (floating_layer, TRUE);
  824.       
  825.       /*  translate the layer -- and any "linked" layers as well  */
  826.       for (layer_list = gdisp->gimage->layers; 
  827.            layer_list; 
  828.            layer_list = g_slist_next (layer_list))
  829.         {
  830.           layer = (Layer *) layer_list->data;
  831.           if (((layer) == gdisp->gimage->active_layer) || 
  832.           layer_linked (layer))
  833.         {
  834.           layer_translate (layer, inc_x, inc_y);
  835.         }
  836.         }
  837.       
  838.       if (floating_layer)
  839.         floating_sel_rigor (floating_layer, TRUE);
  840.       
  841.       break;
  842.       
  843.     case EDIT_FLOATING_SEL_TRANSLATE:
  844.       
  845.       floating_sel_relax (layer, TRUE);
  846.       
  847.       layer_translate (layer, inc_x, inc_y);
  848.       
  849.       floating_sel_rigor (layer, TRUE);
  850.       
  851.       break;
  852.     }
  853.     }
  854.  
  855.   undo_push_group_end (gdisp->gimage);
  856.   gdisplays_flush ();
  857. }
  858.